package com.nhncorp.pleiades.shell;

import java.io.IOException;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;

import com.nhncorp.pleiades.client.LockEventData;
import com.nhncorp.pleiades.client.LockEventHandler;
import com.nhncorp.pleiades.client.LockEventMonitor;
import com.nhncorp.pleiades.client.LockService;
import com.nhncorp.pleiades.client.LockServiceClient;
import com.nhncorp.pleiades.client.PleiadesUser;
import com.nhncorp.pleiades.conf.PleiadesConfiguration;
import com.nhncorp.pleiades.conf.PleiadesConfigured;
import com.nhncorp.pleiades.fs.PleiadesFileSystem;
import com.nhncorp.pleiades.hadoop.New_RPC;
import com.nhncorp.pleiades.hadoop.RemoteException;
import com.nhncorp.pleiades.protocol.LockMetaData;
import com.nhncorp.pleiades.util.StopWatch;
import com.nhncorp.pleiades.util.Tool;
import com.nhncorp.pleiades.util.ToolRunner;

/** Provide command line access to a FileSystem. */
public class ClusterShell extends PleiadesConfigured implements Tool {

  protected PleiadesFileSystem fs;
  protected LockAdminService pleiades;
  public static final SimpleDateFormat dateForm = 
    new SimpleDateFormat("yyyy-MM-dd HH:mm");
  protected static final SimpleDateFormat modifFmt =
    new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  static {
    modifFmt.setTimeZone(TimeZone.getTimeZone("UTC"));
  }
  static final String SETREP_SHORT_USAGE="-setrep [-R] [-w] <rep> <path/file>";
  static final String TAIL_USAGE="-tail [-f] <file>";
  private static final DecimalFormat decimalFormat = new DecimalFormat("#.##");
  private StopWatch watcher;

  /**
   * @throws IOException 
   */
  public ClusterShell() throws IOException {
    this(new PleiadesConfiguration());
  }

  public ClusterShell(PleiadesConfiguration conf) throws IOException {
    super(conf);
  }
  
  protected void init() throws IOException {
    getConf().setQuietMode(true);
    PleiadesUser user = new PleiadesUser("default");
    user.setSessionDisable(true);
    pleiades = new LockAdminClient(user, getConf());
    watcher = new StopWatch(); 
  }

  
  /**
   * Copies from stdin to the indicated file.
   */
//  private void copyFromStdin(Path dst) throws IOException {
//    if (fs.isDirectory(dst)) {
//      throw new IOException("When source is stdin, destination must be a file.");
//    }
//    if (fs.exists(dst)) {
//      throw new IOException("Target " + dst.toString() + " already exists.");
//    }
//    FSDataOutputStream out = fs.create(dst); 
//    try {
//      IOUtils.copyBytes(System.in, out, getConf(), false);
//    } 
//    finally {
//      out.close();
//    }
//  }

  /** 
   * Print from src to stdout.
   */
//  private void printToStdout(Path src) throws IOException {
//    if (fs.isDirectory(src)) {
//      throw new IOException("Source must be a file.");
//    }
//    FSDataInputStream in = fs.open(src);
//    IOUtils.copyBytes(in, System.out, getConf(), true);
//  }
  

  /**
   * Return an abbreviated English-language desc of the byte length
   */
  public static String byteDesc(long len) {
    double val = 0.0;
    String ending = "";
    if (len < 1024 * 1024) {
      val = (1.0 * len) / 1024;
      ending = " KB";
    } else if (len < 1024 * 1024 * 1024) {
      val = (1.0 * len) / (1024 * 1024);
      ending = " MB";
    } else if (len < 1024L * 1024 * 1024 * 1024) {
      val = (1.0 * len) / (1024 * 1024 * 1024);
      ending = " GB";
    } else if (len < 1024L * 1024 * 1024 * 1024 * 1024) {
      val = (1.0 * len) / (1024L * 1024 * 1024 * 1024);
      ending = " TB";
    } else {
      val = (1.0 * len) / (1024L * 1024 * 1024 * 1024 * 1024);
      ending = " PB";
    }
    return limitDecimalTo2(val) + ending;
  }

  public static synchronized String limitDecimalTo2(double d) {
    return decimalFormat.format(d);
  }

  private void printHelp(String cmd) {
    String summary = "pleiades cls is the command to execute lock related commands. " +
      "The full syntax is: \n\n" +
      "pleiades cls [-conf <configuration file>] [-D <property=value>]\n\t" +
      "[-show services | owners]\n\t" +
      "[-listFs <service id> <path>] [-listAll <service id>]\n\t" +
      "[-listByOwner <service id> <owner>] [-listById <service id> <lock id>]\n\t" +
      "[-getMeta <service id> <lockId>] [-getChildrenMeta <service id> <lock id>]\n\t" +
      "[-lock <service id> <owner> <lock id>] [-release <service id> <lock id>]\n\t" +
      "[-releaseByOwner <owner>] [-releaseByService <service id>] [-releaseAll]\n\t" +      
      "[-create <service id> <owner> <path> <overwrite>] [-delete <service id> <path> <recursive>]\n\t" +
      "[-set <service id> <owner> <path> <keyword>]\n\t" +
      "[-help [cmd]]\n";

    String conf ="-conf <configuration file>:  Specify an application configuration file.";
 
    String D = "-D <property=value>:  Use value for given property.";
    
    String show = "-show service | owners: \tList current services | current lock owners.\n";
        
    String listFs = "-listFs <service id> <path>: \tList the nodes under the specified path.\n";

    String listAll = "-listAll <service id>: \tList all the lock information with the specified service\n";

    String listByOwner = "-listByOwner <service id> <owner>: \tList the locks whose owner is the specified one\n";
    
    String listById = "-listById <service id> <lock id>: \tList the locks whose owner is the specified one\n";
    
    String getMeta = "-getMeta <service id> <lockId>: \tGet meta information of the specified lock id(path)\n";
    
    String getChildrenMeta = "-getChildrenMeta <service id> <lockId>: \tGet child meta information of the node under the specified lock id(path)\n";
    
    String lock = "-lock <service id> <owner> <lock id>: \tGet memory lock with specified lock id\n";
    
    String release = "-release <service id> <lock id>: \tRelease the lock\n";
    
    String releaseByOwner = "-releaseByOwner <owner>: \tRelease all the locks whose owner is the specified one\n";
    
    String releaseByService = "-releaseByService <service id>: \tRelease all the locks with the specified service\n";
    
    String releaseAll = "-releaseByOwner <owner>: \tRelease all the locks\n";
    
    String format = "-format : \tRelease all the locks and delete all the nodes\n";
    
    String create = "-create <service id> <owner> <path> <overwrite>: \tGet memory lock and create file and generate event\n";
    
    String delete = "-delete <service id> <path> <recursive>: \tRelease all the locks\n";
    
    String set = "-set <service id> <owner> <path> <keyword>: \tSet key value if file does not exist then create file\n";

    String help = "-help [cmd]: \tDisplays help for given command or all commands if none\n" +
      "\t\tis specified.\n";

    if ("cls".equals(cmd)) {
      System.out.println(summary);
    } else if ("conf".equals(cmd)) {
      System.out.println(conf);
    } else if ("D".equals(cmd)) {
      System.out.println(D);
    } else if ("show".equals(cmd)) {
      System.out.println(listFs);
    } else if ("listFs".equals(cmd)) {
      System.out.println(listFs);
    } else if ("listAll".equals(cmd)) {
      System.out.println(listAll);
    } else if ("listByOwner".equals(cmd)) {
      System.out.println(listByOwner);
    } else if ("listById".equals(cmd)) {
      System.out.println(listById);
    } else if ("getMeta".equals(cmd)) {
      System.out.println(getMeta);
    } else if ("getChildrenMeta".equals(cmd)) {
      System.out.println(getChildrenMeta);
    } else if ("lock".equals(cmd)) {
      System.out.println(lock);
    } else if ("release".equals(cmd)) {
      System.out.println(release);
    } else if ("releaseByOwner".equals(cmd)) {
      System.out.println(releaseByOwner);
    } else if ("releaseByService".equals(cmd)) {
      System.out.println(releaseByService);
    } else if ("releaseAll".equals(cmd)) {
      System.out.println(releaseAll);
    } else if ("create".equals(cmd)) {
      System.out.println(create);
    } else if ("delete".equals(cmd)) {
      System.out.println(delete);
    } else if ("set".equals(cmd)) {
      System.out.println(set);
    } else if ("format".equals(cmd)) {
      System.out.println(format);
    } else if ("help".equals(cmd)) {
      System.out.println(help);
    } else {
      System.out.println(summary);
      System.out.println(show);
      System.out.println(listFs);
      System.out.println(listAll);
      System.out.println(listByOwner);
      System.out.println(listById);
      System.out.println(getMeta);
      System.out.println(getChildrenMeta);
      System.out.println(lock);
      System.out.println(release);
      System.out.println(releaseByOwner);
      System.out.println(releaseByService);
      System.out.println(releaseAll);
      System.out.println(create);
      System.out.println(delete);
      System.out.println(set);
      System.out.println(help);
    }
  }

  /**
   * Displays format of commands.
   * 
   */
  void printUsage(String cmd) {
    if ("-conf".equals(cmd)) {
      System.err.println("Usage: java ClusterShell" + 
                         " [-conf <configuration file>]");
    } else if ("-D".equals(cmd)) {
      System.err.println("Usage: java ClusterShell" + 
                         " [-D <[property=value>]");
    } else if ("-show".equals(cmd)) {
      System.err.println("Usage: java ClusterShell" + 
          " [" + cmd + " services | owners]");
    } else if ("-listFs".equals(cmd)) {
      System.err.println("Usage: java ClusterShell" + 
                         " [" + cmd + " <service id> <path>]");
    } else if ("listAll".equals(cmd) || "releaseByService".equals(cmd)) {
      System.err.println("Usage: java ClusterShell" + 
          " [" + cmd + " <service id>]");
    } else if ("-listById".equals(cmd) || "-getMeta".equals(cmd) ||
               "-getChildrenMeta".equals(cmd)) {
      System.err.println("Usage: java ClusterShell" + 
                         " [" + cmd + " <service id> <lock id>]");
    } else if ("-listByOwner".equals(cmd) || "-release".equals(cmd)) {
      System.err.println("Usage: java ClusterShell" + 
          " [" + cmd + " <service id> <owner>]");
    } else if ("lock".equals(cmd)) {
      System.err.println("Usage: java ClusterShell" + 
          " [" + cmd + " <service id> <owner> <lock id>]");
    } else if ("releaseByOwner".equals(cmd)) {
      System.err.println("Usage: java ClusterShell" + 
          " [" + cmd + " <owner>]");
    } else if ("releaseAll".equals(cmd)) {
      System.err.println("Usage: java ClusterShell" + 
          " [" + cmd + " ]");
    } else if ("format".equals(cmd)) {
      System.err.println("Usage: java ClusterShell" + 
          " [" + cmd + " ]");
    } else if ("create".equals(cmd)) {
      System.err.println("Usage: java ClusterShell" + 
          " [" + cmd + " <service id> <owner> <path> <overwrite>]");
    } else if ("delete".equals(cmd)) {
      System.err.println("Usage: java ClusterShell" + 
          " [" + cmd + " <service id> <path> <recursive>]");
    } else if ("set".equals(cmd)) {
      System.err.println("Usage: java ClusterShell" + 
          " [" + cmd + " <service id> <owner> <path> <keyword>]");
    } else {
      System.err.println("Usage: java ClusterShell");
      System.err.println("           [-show services | owners]");
      System.err.println("           [-listFs <service id> <path>]");
      System.err.println("           [-listAll <service id(optional)>]");
      System.err.println("           [-listByOwner <service id> <owner>]");
      System.err.println("           [-listById <service id> <lock Id>]");
      System.err.println("           [-getMeta <service id> <lockId>]");
      System.err.println("           [-getChildrenMeta <service id> <lock id>]");
      System.err.println("           [-lock <service id> <owner> <lock id>]");
      System.err.println("           [-release <service id> <lock id>]");
      System.err.println("           [-releaseByOwner <owner>]");
      System.err.println("           [-releaseByService <service id>]");
      System.err.println("           [-releaseAll]");
      System.err.println("           [-create <service id> <owner> <path> <overwrite>]");
      System.err.println("           [-delete <service id> <path> <recursive>]");
      System.err.println("           [-set <service id> <owner> <path> <keyword>]");
      System.err.println("           [-format]");
      System.err.println("           [-help [cmd]]");
      System.err.println();
      ToolRunner.printGenericCommandUsage(System.err);
    }
  }
  
  private void show(String cmd) throws IOException{
    if(cmd.equals("services")) {
      
    } else if(cmd.equals("owners")) {
      
    } else {
      System.err.println("           [-show services | owners]");
    }
  }  
  
  private void listFs(String serviceId, String path) throws IOException{
    String[] pathList = null;
    pathList = pleiades.listFs(serviceId, path);
    if(pathList != null) {
      printPath(pathList);
    } else {
      System.out.println("no entry");
    }
  }
  
  private void listAll(String serviceId) throws IOException {
    LockMetaData[] metaDatas = null;
    metaDatas = pleiades.listAll(serviceId);
    if(metaDatas != null) {
      printMetaData(metaDatas);
    } else {
      System.out.println("no entry");
    }
  }
  
  private void listByOwner(String serviceId, String owner) throws IOException{
    LockMetaData[] metaDatas = null;
    metaDatas = pleiades.listByOwner(serviceId, owner);
    if(metaDatas != null) {
      printMetaData(metaDatas, true);
    } else {
      System.out.println("no entry");
    }
  }
  
  private void listById(String serviceId, String lockId) throws IOException{
    LockMetaData[] metaDatas = pleiades.listById(serviceId, lockId);
    if(metaDatas != null) {
      printMetaData(metaDatas, true);
    } else {
      System.out.println("no entry");
    }
    
  } 
  
  private void getMeta(String serviceId, String lockId) throws IOException{
    LockMetaData metaData = pleiades.getMeta(serviceId, lockId);
    if(metaData != null) {
      printMetaData(metaData, true);
    } else {
      System.out.println("no entry");
    }
    
  }   
  
  private void getChildrenMeta(String serviceId, String lockId) throws IOException{
    LockMetaData[] metaDatas = null;
    metaDatas = pleiades.getMetaList(serviceId, lockId);
    if(metaDatas != null) {
      printMetaData(metaDatas, true);
    } else {
      System.out.println("no entry");
    }
  }  
  
  private void lock(String serviceId, String owner, String lockId) throws IOException{
    if(pleiades.lock(serviceId, owner, lockId)) {
      System.out.println("success");
    } else {
      System.out.println("fail");
    }
  }
  
  private void release(String serviceId, String lockId) throws IOException{
    if(pleiades.release(serviceId, lockId)) {
      System.out.println("success");
    } else {
      System.out.println("fail");
    }
  }
  
  private void releaseByOwner(String owner) throws IOException{
    if(pleiades.releaseByOwner(owner)) {
      System.out.println("success");
    } else {
      System.out.println("fail");
    }
  } 
  
  private void releaseByService(String serviceId) throws IOException{
    if(pleiades.releaseByService(serviceId)) {
      System.out.println("success");
    } else {
      System.out.println("fail");
    }
  }   
  
  private void releaseAll() throws IOException{
    if(pleiades.releaseAll()) {
      System.out.println("success");
    } else {
      System.out.println("fail");
    }
  }  
  
  private void doFormat() throws IOException{
    System.err.print("Do you want to format pleiades ? (Y or N) ");
    if (!(System.in.read() == 'Y')) {
      System.err.println("Format aborted in ");
      return;
    }
    while(System.in.read() != '\n'); // discard the enter-key
    if(pleiades.format()) {
      System.out.println("success");
    } else {
      System.out.println("fail");
    }
  }   
  
  private void create(String serviceId, String owner, String path,
      boolean overwrite) throws IOException {
    if(pleiades.create(serviceId, owner, path, overwrite)) {
      System.out.println("success");
    } else {
      System.out.println("fail");
    }
  }
  
  private void delete(String serviceId, String path, boolean recursive)
      throws IOException {
    if(pleiades.delete(serviceId, path, recursive)) {
      System.out.println("success");
    } else {
      System.out.println("fail");
    }
  }
  
  private void set(String serviceId, String owner, String path, String key)
  throws IOException {
    if(pleiades.set(serviceId, owner, path, key)) {
      System.out.println("success");
    } else {
      System.out.println("fail");
    }
  }  
  
  private void doBmtLock(String cmd, String path, int numOfLoops) throws IOException {
    LockService bmtClient = new LockServiceClient(getConf());
    watcher.reset();
    if(cmd.equals("lock")) {
      for(int index=0; index < numOfLoops; ++index) {
        bmtClient.getLock(path + String.valueOf(index), LockService.LockMode.LOCK_EXCLUSIVE);
      }
    } else if(cmd.equals("release")) {
      for(int index=0; index < numOfLoops; ++index) {
        bmtClient.releaseLock(path + String.valueOf(index), LockService.LockMode.LOCK_EXCLUSIVE);
      }
    } 
    System.out.println("elapsed time : " + watcher.elapsedTime());
  }  
  
  private void doBmtEvent(String path, int numOfLoops) throws IOException {
    LockService bmtClient = new LockServiceClient(getConf());
    bmtClient.setEventHandler(new BmtEventHandler(path + String.valueOf(numOfLoops -1)));
    watcher.reset();
    for(int index=0; index < numOfLoops; ++index) {
      bmtClient.createNode(new LockMetaData(path + String.valueOf(index)), true);
    }
  }
  
  public class BmtEventHandler implements LockEventHandler {
    
    private String lastEvent;

    public BmtEventHandler(String event) {
      this.lastEvent = event;
    }

    public void addLockEventMonitor(LockEventMonitor monitor) {      
    }

    public void clientExpired(LockEventData eventData) {
    }

    public void contentsModified(LockEventData eventData) {      
    }

    public void lockExpired(LockEventData eventData) {
    }

    public void masterFailover() {
    }

    public void nodeAdded(LockEventData eventData) {
      if(eventData.getLockId().endsWith(lastEvent)) {
        System.out.println("elapsed time : " + watcher.elapsedTime());
      }
    }

    public void nodeModified(LockEventData eventData) {
    }

    public void nodeRemoved(LockEventData eventData) {
    }

    public void removeEventMonitor(LockEventMonitor monitor) {
    }

    public void sessionExpired() {
    }

    public void sessionSafe() {
    }

    public void sessionWarning() {
    }

    public void clearLockEventMonitors() {
      // TODO Auto-generated method stub
      
    }
    
  }
  
  private synchronized void printPath(String[] pathList) {
    System.out.println("");
    for(String entry : pathList) {
      System.out.println("\t" + entry);
    }
  }  
  
  private synchronized void printMetaData(LockMetaData metaData) {
    printMetaData(metaData, false);
  }
  
  private synchronized void printMetaData(LockMetaData metaData, boolean inDetail) {
    System.out.println("\n\t" + "owner: " + metaData.getCreator());
    System.out.println("\t" + "lock id: " + metaData.getLockId());
    if(inDetail) {
      System.out.println("\t" + "mode: " + (metaData.getLockMode()==0 ? "shared" : "exclusive"));
      System.out.println("\t" + "key: " + metaData.getContentKey());
      System.out.println("\t" + "timestamp: " + metaData.getGenerationNumber());      
    }
  }  
  
  private synchronized void printMetaData(LockMetaData[] metaDatas) {
    printMetaData(metaDatas, false);
  }
  
  private synchronized void printMetaData(LockMetaData[] metaDatas, boolean inDetail) {
    for(LockMetaData entry : metaDatas) {
      System.out.println("\n\t" + "owner: " + entry.getCreator());
      System.out.println("\t" + "lock id: " + entry.getLockId());
      if(inDetail) {
        System.out.println("\t" + "mode: " + (entry.getLockMode()==0 ? "shared" : "exclusive"));
        System.out.println("\t" + "key: " + entry.getContentKey());
        System.out.println("\t" + "timestamp: " + entry.getGenerationNumber());  
      }
    }
  }  
  
  /**
   * run
   */
  public int run(String argv[]) throws Exception {

    if (argv.length < 1) {
      printUsage(""); 
      return -1;
    }

    int exitCode = -1;
    int i = 0;
    String cmd = argv[i++];

    //
    // verify that we have enough command line parameters
    //
    if("-releaseByOwner".equals(cmd) || "-releaseByService".equals(cmd) || "-show".equals(cmd)) {
      if (argv.length != 2) {
        printUsage(cmd);
        return exitCode;
      }
    } else if ("-listByOwner".equals(cmd) || "-listById".equals(cmd) ||
        "-getMeta".equals(cmd) || "-getChildrenMeta".equals(cmd) ||
        "-release".equals(cmd) || "-listFs".equals(cmd)) {
      if (argv.length != 3) {
        printUsage(cmd);
        return exitCode;
      }
    } else if ("-delete".equals(cmd) || "-lock".equals(cmd)) {
      if (argv.length != 4) {
        printUsage(cmd);
        return exitCode;
      }
    } else if ("-create".equals(cmd) || "-set".equals(cmd)) {
      if (argv.length != 5) {
        printUsage(cmd);
        return exitCode;
      }
    } 
    // initialize PleiadesShell
    try {
      init();
    } catch (New_RPC.VersionMismatch v) { 
      System.err.println("Version Mismatch between client and server" +
                         "... command aborted.");
      return exitCode;
    } catch (IOException e) {
      System.err.println("Bad connection to pleiades cell. command aborted.");
      return exitCode;
    }

    exitCode = 0;
    try {
      if("-show".equals(cmd)) {
        show(argv[i++]);        
        
      } else if("-listFs".equals(cmd)) {
        listFs(argv[i++], argv[i++]);
        
      } else if ("-listAll".equals(cmd)) {
        if (i < argv.length) {
          listAll(argv[i++]);
        } else {
          listAll("");
        }
      } else if ("-listByOwner".equals(cmd)) {
        listByOwner(argv[i++], argv[i++]);
        
      } else if ("-listById".equals(cmd)) {
        listById(argv[i++], argv[i++]);
        
      } else if ("-getMeta".equals(cmd)) {
        getMeta(argv[i++], argv[i++]);
        
      } else if ("-getChildrenMeta".equals(cmd)) {
        getChildrenMeta(argv[i++], argv[i++]);
        
      } else if ("-lock".equals(cmd)) {
        lock(argv[i++], argv[i++], argv[i++]);
        
      } else if ("-release".equals(cmd)) {
        release(argv[i++], argv[i++]);
        
      } else if ("-releaseByOwner".equals(cmd)) {
        releaseByOwner(argv[i++]);
        
      } else if ("-releaseByService".equals(cmd)) {
        releaseByService(argv[i++]);
        
      } else if ("-releaseAll".equals(cmd)) {
        releaseAll();
        
      } else if ("-format".equals(cmd)) {
        doFormat();
        
      } else if ("-create".equals(cmd)) {
        create(argv[i++], argv[i++], argv[i++], Boolean.parseBoolean(argv[i++]));
        
      } else if ("-delete".equals(cmd)) {
        delete(argv[i++], argv[i++], Boolean.parseBoolean(argv[i++]));
        
      } else if ("-set".equals(cmd)) {
        set(argv[i++], argv[i++], argv[i++], argv[i++]);
        
      } else if ("-bmtLock".equals(cmd)) {
        doBmtLock(argv[i++], argv[i++], Integer.parseInt(argv[i++]));
        
      } else if ("-bmtEvent".equals(cmd)) {
        doBmtEvent(argv[i++], Integer.parseInt(argv[i++]));
        
      } else if ("-help".equals(cmd)) {
        if (i < argv.length) {
          printHelp(argv[i]);
        } else {
          printHelp("");
        }
      } else {
        exitCode = -1;
        System.err.println(cmd.substring(1) + ": Unknown command");
        printUsage("");
      }
    } catch (RemoteException e) {
      //
      // This is a error returned by pleiades server. Print
      // out the first line of the error mesage, ignore the stack trace.
      exitCode = -1;
      try {
        String[] content;
        content = e.getLocalizedMessage().split("\n");
        System.err.println(cmd.substring(1) + ": " + 
                           content[0]);
      } catch (Exception ex) {
        System.err.println(cmd.substring(1) + ": " + 
                           ex.getLocalizedMessage());  
      }
    } catch (IOException e) {
      //
      // IO exception encountered locally.
      // 
      exitCode = -1;
      System.err.println(cmd.substring(1) + ": " + 
                         e.getLocalizedMessage());  
    } catch (RuntimeException re) {
      exitCode = -1;
      System.err.println(cmd.substring(1) + ": " + re.getLocalizedMessage());  
    } finally {
    }
    return exitCode;
  }

  public void close() throws IOException {
    if(pleiades != null) {
      pleiades.close();
      pleiades = null;
    }
  }

  /**
   * main() has some simple utility methods
   */
  public static void main(String argv[]) throws Exception {
    ClusterShell shell = new ClusterShell();
    int res;
    try {
      res = ToolRunner.run(shell, argv);
    } finally {
      shell.close();
    }
    System.exit(res);
  }
}
